﻿// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This file is part of CodingEditor.
// Note:	This project is derived from Peter Project
//			(hosted on sourceforge and codeplex)
//
// Copyright (c) 2008-2009, CE Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


namespace CE.Main
{
	using System;
	using System.Collections;
    using System.Drawing;
	using System.IO;
	using System.Text;
	using System.Text.RegularExpressions;
	using System.Web;
	using System.Windows.Forms;

	using CE.API;
	using CE.Classes;
	using CE.CustomControls;

	using ICSharpCode.TextEditor;
	using ICSharpCode.TextEditor.Actions;
	using ICSharpCode.TextEditor.Document;

	using WeifenLuo.WinFormsUI.Docking;

	#region Delegates

	public delegate void CloseDelegate();
	public delegate void LoadFileDelegate(string text);

	#endregion Delegates

	/// <summary>
	/// This is the main editing component.
	/// </summary>
	public sealed class SourceEditor : DockContent, ICEPluginTab, ICEHtml, IDisposable
	{
		#region Fields

		private static short _count /* = 0*/;
		private static MainForm _mainForm;
		private bool _isFirstColor;
		private GListBox _autoComplete;
		private bool _changed;
		private CloseDelegate _closeDelegate;
		private TextEditorControl _textEditor;
		private Encoding _encoding;
		private FileSystemWatcher _fileSystemWatcher;
		private int _findPosition;
		private ICEPluginHost _pluginHost;
		private LoadFileDelegate _loadFileDelegate;
		private string _project;
		private HtmlToolTip _toolTip;

        //private static char[] stopChars = new char [] {
        //     '(', ')', ' ', '-', '+', '=', '*', '&', '^',
        //     '%', '$', '#', '@', '!', '{', '}', '[', ']',
        //     '|', '\\', ';', '\'', ',', '\"', ',', '.',
        //     '<', '>', '/', '?', '`', '~', '\t', '\r','\n'
        //};

        private const string _stopChars = "() -+=*&^%$#@!{}[]|\\;,\'\".<>/?`~\t\r\n";

		#endregion Fields

		#region Constructors

		public SourceEditor(string tabTitle, MainForm main)
		{
			InitializeComponent();
			// Set up the Parent Tab...
			TabText = tabTitle;
			if (_mainForm == null)
				_mainForm = main;
			Initialize();
			InitTextEditor();
		}

		#endregion Constructors

		#region Properties

        public static short Count
        {
            get { return _count; }
            set { _count = value; }
        }

		/// <summary>
		/// Gets if this Control can Cut...
		/// </summary>
		public bool AbleToCopy
		{
			get { return true; }
		}

		/// <summary>
		/// Gets if this Control can Cut...
		/// </summary>
		public bool AbleToCut
		{
			get { return true; }
		}

		/// <summary>
		/// Gets if this Control can Delete...
		/// </summary>
		public bool AbleToDelete
		{
			get { return (_textEditor.Document.TextContent != string.Empty) ? true : false; }
		}

		/// <summary>
		/// Gets if this Control can Paste...
		/// </summary>
		public bool AbleToPaste
		{
			get { return true; }
		}

		/// <summary>
		/// Gets if we are able to do a Redo Action...
		/// </summary>
		public bool AbleToRedo
		{
			get { return _textEditor.EnableRedo; }
		}

		/// <summary>
		/// Gets if this Control can Save...
		/// </summary>
		public bool AbleToSave
		{
			get { return true; }
		}

		/// <summary>
		/// Gets if this Control can Select All...
		/// </summary>
		public bool AbleToSelectAll
		{
			get { return true; }
		}

		/// <summary>
		/// Gets if we are able to do an Undo Action...
		/// </summary>
		public bool AbleToUndo
		{
			get { return _textEditor.EnableUndo; }
		}

		public TextEditorControl CurrentEditor
		{
			get { return _textEditor; }
		}

		/// <summary>
		/// Get current encoding
		/// </summary>
		public Encoding Encoding
		{
			get { return _textEditor.Encoding; }
			set { _textEditor.Encoding = value; }
		}

		/// <summary>
		/// Gets the File Name of the Document...
		/// </summary>
		public string FileName
		{
			get { return _textEditor.FileName; }
		}

		/// <summary>
		/// Gets or Sets the Highligthing for the Editor...
		/// </summary>
		public string Highlighting
		{
			get { return _textEditor.Document.HighlightingStrategy.Name; }

			set{
				try {
					_textEditor.Document.HighlightingStrategy = HighlightingManager.Manager.FindHighlighter(value);
					switch (value) {
					    case "XML":
						    _textEditor.Document.FoldingManager.FoldingStrategy = new cXmlFoldingStrategy();
						    _textEditor.Document.FoldingManager.UpdateFoldings(null, null);
						    break;
					    case "C#":
						    _textEditor.Document.FormattingStrategy = new CSharpFormattingStrategy();
						    _textEditor.Document.FoldingManager.FoldingStrategy = new CSharpFoldingStrategy();
						    _textEditor.Document.FoldingManager.UpdateFoldings(null, null);
						    //m_MainForm.EnableCodeCompletion(true);
						    break;
					    case "C++.NET":
						    _textEditor.Document.FormattingStrategy = new CSharpFormattingStrategy();
						    break;
					}
				}
				catch (Exception ex) {
					Program.ShowError(ex.Message);
				}
			}
		}

		/// <summary>
		/// Sets the Host Control...
		/// </summary>
		public ICEPluginHost Host
		{
			get { return _pluginHost; }

			set { _pluginHost = value; }
		}

		/// <summary>
		/// Gets if the Editor needs to be Saved...
		/// </summary>
		public bool NeedsSaving
		{
			get { return _changed; }
		}

		/// <summary>
		/// Gets or Sets the Project related to the file...
		/// </summary>
		public string Project
		{
			get { return _project; }

			set { _project = value; }
		}

		/// <summary>
		/// Gets the Selected Text...
		/// </summary>
		public string Selection
		{
			get{
				if (_textEditor.ActiveTextAreaControl.SelectionManager.HasSomethingSelected) {
					return _textEditor.ActiveTextAreaControl.SelectionManager.SelectedText;
				}
				return string.Empty;
			}
		}

		#endregion Properties

		#region Methods

		/// <summary>
		/// Closes this Editor...
		/// </summary>
		public bool CloseTab()
		{
			if (_changed) {
				string file = FileName ?? TabText;
				DialogResult responce = MessageBox.Show(_mainForm, "Do you want to Save " + file + "?", "CodingEditor",
				                                    MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
				switch (responce) {
				    case DialogResult.Yes:
					    if (FileName == null)
						    _pluginHost.SaveAsCurrentFile(this);
					    else
						    Save();
					    break;
				    case DialogResult.No:
					    _changed = false;
					    break;
				    case DialogResult.Cancel:
					    return false;
				}
			}
			if (_fileSystemWatcher != null)
				_fileSystemWatcher.EnableRaisingEvents = false;
			_mainForm.UpdateCaretPosition(0, 0, 0, null);
			//this.Close();
			//Dispose(true);
			return true;
		}

		// TODO: Complete ColumnAdd method and check it's functionality
        // This method is used only by the ColumnEditor form.
		public void ColumnAdd(string text)
		{
			//string txt = m_Editor.Text.Substring(m_Editor.ActiveTextAreaControl.Caret.Line * m_Editor.ActiveTextAreaControl.Caret.Column);

			string editorTextContent = _textEditor.Text;

			Regex re = new Regex("\n");
			MatchCollection matches = re.Matches(editorTextContent);
			StringBuilder strBuilder = new StringBuilder(editorTextContent);
			Console.WriteLine("OUTPUT: MATCHES = " + matches.Count.ToString());
			foreach (char c in strBuilder.ToString()) {

			}

			/*
			   for (int i = m_Editor.ActiveTextAreaControl.Caret.Line + 1; i < matches.Count + 1; ++i)
			   {
			    Goto(i, m_Editor.ActiveTextAreaControl.Caret.Column + 1);
			    m_Editor.
			   }*/

			/*
			   while (m_Editor.ActiveTextAreaControl.Caret.Line <=
			    (m_Editor.ActiveTextAreaControl.Caret.Line - remainingLines))
			   {
			    m_Editor.ActiveTextAreaControl.Caret.Line++;
			   }*/
		}

		/// <summary>
		/// Clipboard Copy Action...
		/// </summary>
		public void Copy()
		{
			_textEditor.ActiveTextAreaControl.TextArea.ClipboardHandler.Copy(null, null);
		}

		/// <summary>
		/// Clipboard Cut Action...
		/// </summary>
		public void Cut()
		{
			_textEditor.ActiveTextAreaControl.TextArea.ClipboardHandler.Cut(null, null);
		}

		/// <summary>
		/// Clipboard Delete Action...
		/// </summary>
		public void Delete()
		{
			_textEditor.ActiveTextAreaControl.TextArea.ClipboardHandler.Delete(null, null);
		}

		public void Duplicate()
		{
			if (_textEditor.ActiveTextAreaControl.SelectionManager.HasSomethingSelected) {
				string selection = _textEditor.ActiveTextAreaControl.SelectionManager.SelectedText;
				int pos = _textEditor.ActiveTextAreaControl.SelectionManager.SelectionCollection[0].EndOffset;
				_textEditor.Document.Insert(pos, selection);

				_textEditor.ActiveTextAreaControl.TextArea.Invalidate();
			}
		}

		/// <summary>
		/// Finds the Next Occurance of the given Pattern...
		/// </summary>
		/// <param name="reg">Pattern to Find.</param>
		/// <param name="searchUp"></param>
		public bool FindNext(Regex regex, bool searchUp)
		{
			_pluginHost.ChangeStatus("Searching for " + regex);
			Match match;
			if (searchUp) {
				MatchCollection matchCollection = regex.Matches(_textEditor.Document.TextContent.Substring(0,
                    _textEditor.ActiveTextAreaControl.Caret.Offset));
				if (matchCollection.Count > 0) {
					match = matchCollection[matchCollection.Count - 1];
					HighlightMatch( match, searchUp);
				} else {
					matchCollection = regex.Matches(_textEditor.Document.TextContent);
					if (matchCollection.Count > 0) {
						match = matchCollection[matchCollection.Count - 1];
						HighlightMatch( match, searchUp);
					} else {
						CouldNotFind( regex);
						return false;
					}
				}
			} else {
				match = regex.Match(_textEditor.Document.TextContent, _textEditor.ActiveTextAreaControl.Caret.Offset);
				if (!match.Success) {
					match = regex.Match(_textEditor.Document.TextContent);
				}

				if (match.Success) {
					HighlightMatch( match, searchUp);
				} else {
					CouldNotFind( regex);
					return false;
				}
				_textEditor.ActiveTextAreaControl.TextArea.Focus();
			}

			return true;
		}

		/// <summary>
		/// Gets the Text of the Editor...
		/// </summary>
		/// <returns>Text in the Editor</returns>
		public string GetText()
		{
			return _textEditor.Document.TextContent;
		}

		public void Goto(int line, int col)
		{
			_textEditor.ActiveTextAreaControl.Caret.Line = line;
			_textEditor.ActiveTextAreaControl.Caret.Column = col;
		}

		/// <summary>
		/// Goes to the next(true) or previous(false) mark...
		/// </summary>
		/// <param name="forward">True(next) or Previous(false)</param>
		public void GotoMark(bool forward)
		{
			Bookmark b = (forward) ?
			             _textEditor.Document.BookmarkManager.GetNextMark(_textEditor.ActiveTextAreaControl.Caret.Line) :
			             _textEditor.Document.BookmarkManager.GetPrevMark(_textEditor.ActiveTextAreaControl.Caret.Line);
			_textEditor.ActiveTextAreaControl.CenterViewOn(b.LineNumber, 0);
			_textEditor.ActiveTextAreaControl.Caret.Line = b.LineNumber;
		}

		public void LinkClick(HtmlElement activeElement)
		{
			int line;
			if (Int32.TryParse(activeElement.InnerText, out line)) {
				--line;
				LineSegment lineSeg = _textEditor.Document.GetLineSegment(line);
				_textEditor.ActiveTextAreaControl.Caret.Position = _textEditor.Document.OffsetToPosition(lineSeg.Offset);
				_textEditor.ActiveTextAreaControl.CenterViewOn(line, 0);
			} else {
				string filePath = activeElement.GetAttribute("h");
				filePath = HttpUtility.UrlDecode(filePath);
				filePath = filePath.Substring(8);
				filePath = filePath.Replace('/', '\\');
				string offset = activeElement.GetAttribute("offset");
				string tabName = Path.GetFileName(filePath);
				Icon fileIcon = Host.GetFileIcon( filePath, false);
				_pluginHost.CreateEditor( filePath,  tabName,  fileIcon, this);
				_mainForm.GetEditor( filePath).ScrollTo(Convert.ToInt32(offset));
				_mainForm.GetEditor( filePath).Project = _project;
			}
		}

		/// <summary>
		/// Loads the Given File...
		/// </summary>
		/// <param name="filePath">Path to File.</param>
		public void LoadFile(string filePath)
		{
			FileInfo fileInfo = new FileInfo(filePath);
			this.TabText = fileInfo.Name;
			ToolTipText = filePath;

			_textEditor.LoadFile(filePath, true, true);

			_encoding = _textEditor.Encoding;
			_changed = false;
			RemoveChangeStar();

			if (string.IsNullOrEmpty(fileInfo.Extension)) {
				_textEditor.Document.HighlightingStrategy = HighlightingManager.Manager.FindHighlighter("HTML");
			}
			if (fileInfo.IsReadOnly) {
				_textEditor.Document.ReadOnly = true;
				Bitmap b = Icon.ToBitmap();
				using (Graphics g = Graphics.FromImage(b))
				      {
					      //Image img = m_MainForm.GetInternalImage("_lock");
					      //g.DrawImage(img, new Point(0, 0));
					      Icon = Icon.FromHandle(b.GetHicon());
				      }
			}
			SetupFileWatcher();
			_textEditor.ActiveTextAreaControl.TextArea.Focus();
		}

		/// <summary>
		/// Comments the line
		/// </summary>
		public void MakeLineComment()
		{
			new ToggleComment().Execute(_textEditor.ActiveTextAreaControl.TextArea);
		}

		/// <summary>
		/// Marks all of the Occurances of the given Pattern...
		/// </summary>
		/// <param name="reg">Pattern to Mark.</param>
		public void MarkAll( Regex reg)
		{
			MatchCollection mc = reg.Matches(_textEditor.Document.TextContent);
			foreach (Match m in mc) {
				int line = _textEditor.Document.GetLineNumberForOffset(m.Index);
				_textEditor.Document.BookmarkManager.AddMark(new Bookmark(_textEditor.Document, line));
			}
			_textEditor.ActiveTextAreaControl.Invalidate(true);
			_textEditor.ActiveTextAreaControl.TextArea.Focus();
		}

		/// <summary>
		/// Clipboard Paste Action...
		/// </summary>
		public void Paste()
		{
			_textEditor.ActiveTextAreaControl.TextArea.ClipboardHandler.Paste(null, null);
		}

		public void Print(bool showPrintDialog)
		{
			try {
				var dlg = new PrintDialog { Document = _textEditor.PrintDocument };
				if (showPrintDialog)
					dlg.ShowDialog();
				else
					dlg.Document.Print();
			}
			catch (Exception ex) {
				Program.ShowError(ex.Message);
			}
		}

		public void Print()
		{
		}

		public void PrintPreview()
		{
			var dlg = new PrintPreviewDialog { Document = _textEditor.PrintDocument };
			dlg.ShowDialog();
		}

		/// <summary>
		/// Edit Redo Action...
		/// </summary>
		public void Redo()
		{
			_textEditor.Document.UndoStack.Redo();
		}

		/// <summary>
		/// Removes all the Marks from the Editor...
		/// </summary>
		public void RemoveAllMarks()
		{
			_textEditor.Document.BookmarkManager.Clear();
			_textEditor.ActiveTextAreaControl.Invalidate(true);
		}

		/// <summary>
		/// Replaces all Occurances of the Given Pattern...
		/// </summary>
		/// <param name="reg">Pattern to Replace.</param>
		/// <param name="replaceWith"></param>
		public void ReplaceAll( Regex reg,   string replaceWith)
		{
			string replaced = reg.Replace(_textEditor.Document.TextContent, replaceWith);
			if (replaced != _textEditor.Document.TextContent) {
				_textEditor.Document.Replace(0, _textEditor.Document.TextLength, replaced);
			} else {
				_pluginHost.ChangeStatus("No Occurrences of '" + reg + "' found in " + TabText + ".");
			}
			_textEditor.ActiveTextAreaControl.TextArea.Focus();
		}

		/// <summary>
		/// Replaces the Next Occurance of the Given Pattern...
		/// </summary>
		/// <param name="reg">Pattern to Replace.</param>
		/// <param name="replaceWith"></param>
		public void ReplaceNext( Regex reg,  string replaceWith, bool searchUp)
		{
			FindNext( reg, searchUp);
			if (_findPosition != -1) {
				_textEditor.ActiveTextAreaControl.Caret.Position = _textEditor.Document.OffsetToPosition(_findPosition);
				string replaced = reg.Replace(_textEditor.Document.TextContent, replaceWith, 1, _findPosition);
				_textEditor.Document.Replace(0, _textEditor.Document.TextLength, replaced);
				_textEditor.ActiveTextAreaControl.TextArea.Focus();
			}
			_textEditor.ActiveTextAreaControl.TextArea.Focus();
		}

		/// <summary>
		/// Saves the Current Document...
		/// </summary>
		public void Save()
		{
			string fileName = _textEditor.FileName;
			SaveAs( fileName);
		}

		/// <summary>
		/// Saves the Document As...
		/// </summary>
		/// <param name="filePath">Path to File to Save As.</param>
		public void SaveAs( string filePath)
		{
			if (_fileSystemWatcher != null)
				_fileSystemWatcher.EnableRaisingEvents = false;

			if (string.IsNullOrEmpty(Path.GetExtension(filePath)))
				filePath += ".txt";

			var f = new FileInfo(filePath);
			if (f.Exists && f.IsReadOnly) {
				if (MessageBox.Show(_mainForm,
				                    "The File \"" + filePath + "\" is Read Only.\nDo you want to save under a different file name?",
				                    "CodingEditor", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {
					_pluginHost.SaveAsCurrentFile(this);
					return;
				}
				return;
			}

			ToolTipText = filePath;
			TabText = Path.GetFileName(filePath);
			Icon = _pluginHost.GetFileIcon( filePath, false);
			_textEditor.SaveFile(filePath);
			bool reload = false;
			if (string.IsNullOrEmpty(_textEditor.FileName)) {
				reload = true;
			} else {
				if (Path.GetExtension(filePath) != Path.GetExtension(_textEditor.FileName)) {
					reload = true;
				}
			}

			if (reload) {
				_textEditor.Document.HighlightingStrategy = HighlightingManager.Manager.FindHighlighterForFile(filePath);
			}
			_changed = false;
			RemoveChangeStar();

			SetupFileWatcher();
		}

		public void ScrollTo(int offset)
		{
			if (offset > _textEditor.Document.TextLength) {
				return;
			}
			int line = _textEditor.Document.GetLineNumberForOffset(offset);
			_textEditor.ActiveTextAreaControl.Caret.Position = _textEditor.Document.OffsetToPosition(offset);
			_textEditor.ActiveTextAreaControl.ScrollTo(line); //.CenterViewOn(line, 0);
		}

		/// <summary>
		/// Selects All the Text of the Document...
		/// </summary>
		public void SelectAll()
		{
			_textEditor.ActiveTextAreaControl.TextArea.ClipboardHandler.SelectAll(null, null);
		}

		/// <summary>
		/// Selects the word at the given offset...
		/// </summary>
		/// <param name="line">Line Word is on.</param>
		/// <param name="offset">Offset Word is at.</param>
		/// <param name="wordLen">Length of Word.</param>
		public void SelectWord(int line, int offset, int wordLen)
		{
			_textEditor.ActiveTextAreaControl.ScrollTo(line);
			_textEditor.ActiveTextAreaControl.Caret.Line = line;
			_textEditor.ActiveTextAreaControl.SelectionManager.SetSelection(
			        _textEditor.Document.OffsetToPosition(_textEditor.ActiveTextAreaControl.Caret.Offset + offset),
			        _textEditor.Document.OffsetToPosition(_textEditor.ActiveTextAreaControl.Caret.Offset + offset + wordLen));
			_textEditor.ActiveTextAreaControl.TextArea.Focus();
		}

		/// <summary>
		/// Sets the Context Menu for the Editor
		/// </summary>
		/// <param name="ctx">Context Menu to use.</param>
		public void SetContextMenuStrip(ContextMenuStrip ctx)
		{
			_textEditor.ActiveTextAreaControl.TextArea.ContextMenuStrip = ctx;
		}

		/// <summary>
		/// Sets the Text of the Editor...
		/// </summary>
		/// <param name="text">Text for the Editor</param>
		public void SetText(string text)
		{
			_textEditor.Document.TextContent = text;
			_changed = false;
			RemoveChangeStar();
		}

		/// <summary>
		/// Sets the Text of the Editor...
		/// </summary>
		/// <param name="text">Text for the Editor</param>
		public void SetTextChanged(string text)
		{
			_textEditor.Document.TextContent = text;
		}

		/// <summary>
		/// Sets up the Editor...
		/// </summary>
		/// <param name="config">XmlNode that holds the Configuration.</param>
		public void SetupEditor(ref Common.EditorConfig config)
		{
			_textEditor.ShowEOLMarkers = config.ShowEOL;
			_textEditor.ShowInvalidLines = config.ShowInvalidLines;
			_textEditor.ShowSpaces = config.ShowSpaces;
			_textEditor.ShowTabs = config.ShowTabs;
			_textEditor.ShowMatchingBracket = config.ShowMatchingBracket;
			_textEditor.ShowLineNumbers = config.ShowLineNumbers;
			_textEditor.ShowHRuler = config.ShowHRuler;
			_textEditor.ShowVRuler = config.ShowVRuler;
			_textEditor.EnableFolding = config.EnableCodeFolding;

            _textEditor.BracketHighlightInnerColor = config.BracketHighlightInnerColor;
            _textEditor.BracketHighlightOutlineColor = config.BracketHighlightOutlineColor;

			_textEditor.Font = config.EditorFont;
			_textEditor.ConvertTabsToSpaces = config.ConvertTabs;
			_textEditor.TabIndent = config.TabIndent;
			_textEditor.VRulerRow = 100; //config.VerticalRulerCol;
			//this.m_Editor.UseAntiAliasFont = config.UseAntiAlias; // #develop 2
			// #develop 3
			if (config.UseAntiAlias) {
				this._textEditor.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
			}
			_textEditor.AllowCaretBeyondEOL = config.AllowCaretBeyondEOL;
			_textEditor.TextEditorProperties.AutoInsertCurlyBracket = config.AutoInsertBracket;
			_textEditor.LineViewerStyle = (config.HighlightCurrentLine) ? LineViewerStyle.FullRow : LineViewerStyle.None;
			switch (config.BracketMatchingStyle.ToLower()) {
			    case "before":
				    _textEditor.BracketMatchingStyle = BracketMatchingStyle.Before;
				    break;
			    case "after":
				    _textEditor.BracketMatchingStyle = BracketMatchingStyle.After;
				    break;
			}
			switch (config.IndentStyle.ToLower()) {
			    case "auto":
				    _textEditor.IndentStyle = IndentStyle.Auto;
				    break;
			    case "none":
				    _textEditor.IndentStyle = IndentStyle.None;
				    break;
			    case "smart":
				    _textEditor.IndentStyle = IndentStyle.Smart;
				    break;
			}
		}

		/// <summary>
		/// Sets up the file watcher...
		/// </summary>
		public void SetupFileWatcher()
		{
			// Remove Events...
			if (_fileSystemWatcher != null) {
				_fileSystemWatcher.Changed -= m_FSW_Changed;
				_fileSystemWatcher.Deleted -= m_FSW_Deleted;
				_fileSystemWatcher.Renamed -= m_FSW_Renamed;
			}

			// Create new FileWatcher...
			_fileSystemWatcher = new FileSystemWatcher(Path.GetDirectoryName(_textEditor.FileName), Path.GetFileName(_textEditor.FileName)){
				EnableRaisingEvents = true,
				IncludeSubdirectories = false
			};

			// Add Events...
			_fileSystemWatcher.Changed += m_FSW_Changed;
			_fileSystemWatcher.Deleted += m_FSW_Deleted;
			_fileSystemWatcher.Renamed += m_FSW_Renamed;
		}

		/// <summary>
		/// Converts text to lower case
		/// </summary>
		public void ToLowerCase()
		{
			new ToLowerCase().Execute(_textEditor.ActiveTextAreaControl.TextArea);
		}

		/// <summary>
		/// Converts text to upper case
		/// </summary>
		public void ToUpperCase()
		{
			new ToUpperCase().Execute(_textEditor.ActiveTextAreaControl.TextArea);
		}

		/// <summary>
		/// Toggles a mark at the current line...
		/// </summary>
		public void ToggleMark()
		{
			_textEditor.Document.BookmarkManager.ToggleMarkAt(_textEditor.ActiveTextAreaControl.Caret.Line);
			_textEditor.ActiveTextAreaControl.Invalidate(true);
		}

		/// <summary>
		/// Edit Undo Action...
		/// </summary>
		public void Undo()
		{
			_textEditor.Document.UndoStack.Undo();
		}

		public void UpdateCaretPos()
		{
			_mainForm.UpdateCaretPosition(_textEditor.ActiveTextAreaControl.Caret.Offset, _textEditor.ActiveTextAreaControl.Caret.Line + 1,
			                               _textEditor.ActiveTextAreaControl.Caret.Column + 1,
			                               _textEditor.ActiveTextAreaControl.Caret.CaretMode.ToString());
		}

		/// <summary>
		/// Splits the text view area in two.
		/// </summary>
		internal void Split()
		{
			_textEditor.Split();
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing) {
				for (short index = 0; index < this.Controls.Count; ++index) {
					Controls[index].Dispose();
				}
			}
			base.Dispose(disposing);
		}

		/// <summary>
		/// Overrides the Persist String for the Docking Control...
		/// </summary>
		/// <returns>Newly Formed Persist String.</returns>
		protected override string GetPersistString()
		{
			RemoveChangeStar();
			return (FileName == null)
			       ? GetType() + "|" + TabText + "|none|" + _textEditor.Document.TextContent
			       : GetType() + "|" + TabText + "|" + FileName + "|" +
			       _textEditor.ActiveTextAreaControl.Caret.Offset + "|";
		}

        
		private static bool CheckStop(char val)
        {
            return (!_stopChars.Contains(val.ToString()));
            #region commented out
            //switch (val) {
            //    case '(':
            //    case ')':
            //    case ' ':
            //    case '-':
            //    case '+':
            //    case '=':
            //    case '*':
            //    case '&':
            //    case '^':
            //    case '%':
            //    case '$':
            //    case '#':
            //    case '@':
            //    case '!':
            //    case '{':
            //    case '}':
            //    case '[':
            //    case ']':
            //    case '|':
            //    case '\\':
            //    case ';':
            //    case '\'':
            //    case ':':
            //    case '\"':
            //    case ',':
            //    case '.':
            //    case '<':
            //    case '>':
            //    case '/':
            //    case '?':
            //    case '`':
            //    case '~':
            //    case '\t':
            //    case '\r':
            //    case '\n':
            //        return false;
            //    default:
            //        return true;
            //}
            #endregion
        }

		/// <summary>
		/// Enables files to be dropped in the dock window...
		/// </summary>
		/// <param name="sender">Text Area</param>
		/// <param name="e">Events</param>
		private static void TextArea_DragEnter(object sender, DragEventArgs e)
		{
			if (e.Data.GetDataPresent(DataFormats.FileDrop, false)) {
				e.Effect = DragDropEffects.All;
			}
		}

		private void Caret_CaretModeChanged(object sender, EventArgs e)
		{
			UpdateCaretPos();
		}

		private void Caret_Change(object sender, EventArgs e)
		{
			UpdateCaretPos();
		}


		private void CouldNotFind( Regex reg)
		{
			_findPosition = -1;
			MessageBox.Show(_mainForm, "No Occurrences of '" + reg + "' found.", "CodingEditor", MessageBoxButtons.OK,
			                MessageBoxIcon.Information);
			_pluginHost.ChangeStatus(string.Empty);
		}

		/// <summary>
		/// Close Delegate Method...
		/// </summary>
		private void DelClose()
		{
			if (MessageBox.Show(_mainForm, _textEditor.FileName + " has been deleted. Do you want to close this file's tab?",
			                    "CodingEditor", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes) {
				_changed = false;
				CloseTab();
			}
		}

		/// <summary>
		/// Reload File Delegate...
		/// </summary>
		/// <param name="file">Path to File.</param>
		private void DelReload(string file)
		{
			if (MessageBox.Show(_mainForm, _textEditor.FileName + " has changed. Do you want to reload the file?",
			                    "CodingEditor", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes) {
				LoadFile(file);
			}
		}

		/// <summary>
		/// Occurs when the document changes...
		/// </summary>
		/// <param name="sender">Document</param>
		/// <param name="e">DocumentEvents</param>
		private void Document_DocumentChanged(object sender, DocumentEventArgs e)
		{
			if (!_changed) {
				TabText = "*" + TabText;
				_changed = true;
				_mainForm.UpdateTitleBar(false);
			}
			_mainForm.ChangeUIAccessibility((GetText().Length > 0));
		}

		/// <summary>
		/// Returns the caret line number
		/// </summary>
		/// <returns></returns>
//  COMMENTED BY CODEIT.RIGHT
//        private int GetLineNum()
//        {
//            return m_Editor.ActiveTextAreaControl.Caret.Line + 1;
//        }

		private void HighlightMatch( Match m, bool searchUp)
		{
			_textEditor.ActiveTextAreaControl.SelectionManager.SetSelection(
			        _textEditor.Document.OffsetToPosition(m.Index),
			        _textEditor.Document.OffsetToPosition(m.Index + m.Length));

			_textEditor.ActiveTextAreaControl.Caret.Position =
			        searchUp ? _textEditor.Document.OffsetToPosition(m.Index) :
			        _textEditor.Document.OffsetToPosition(m.Index + m.Length);

			_pluginHost.ChangeStatus(string.Empty);
			_findPosition = m.Index;
		}

		/// <summary>
		/// Highlight matching words
		/// </summary>
		/// <param name="reg">Word to search & highlight</param>
		private bool HighlightMatchingWords(string wordToHighlight)
		{
            // TODO: Optimize highlighting matching words by highlighting only the visible area
            // of the editor. This method is not working as expected.
			if (wordToHighlight.Contains(" ")) {
				ClearAllMarkers();
				return false;
			}

			Regex regex = new Regex(wordToHighlight);

			_isFirstColor = true;
			ClearAllMarkers();
			Color hColor = Color.FromArgb(117, 217, 117);
			_isFirstColor = false;
			MatchCollection mc = regex.Matches(_textEditor.Document.TextContent);
			if (mc.Count > 1) {
				foreach (Match m in mc) {
					TextMarker marker = new TextMarker(m.Index, m.Length, TextMarkerType.SolidBlock, hColor);
                    //_textEditor.ActiveTextAreaControl.TextArea.TextView.AddMarkerToDraw(marker);
					_textEditor.Document.MarkerStrategy.AddMarker(marker);
					if (!_isFirstColor)
						hColor = Color.FromArgb(155, 255, 155);
				}
                return true;
			} else {
				ClearAllMarkers();
			}
            return false;
		}


		private void InitTextEditor()
		{
			_textEditor = new TextEditorControl
			{
				Dock = DockStyle.Fill,
				IsIconBarVisible = true,
				ShowMatchingBracket = true,
				IndentStyle = IndentStyle.Smart
			};
			_textEditor.BorderStyle = BorderStyle.Fixed3D;
			_textEditor.Document.FoldingManager.FoldingStrategy = new CE.Classes.CodeFoldingStrategy();
			_textEditor.ActiveTextAreaControl.TextArea.AllowDrop = true;
			_textEditor.ActiveTextAreaControl.TextArea.DragEnter += TextArea_DragEnter;
			_textEditor.ActiveTextAreaControl.TextArea.DragDrop += TextArea_DragDrop;
			_textEditor.ActiveTextAreaControl.TextArea.MouseDown += TextArea_MouseDown;
			_textEditor.ActiveTextAreaControl.Caret.PositionChanged += Caret_Change;
			_textEditor.ActiveTextAreaControl.Caret.CaretModeChanged += Caret_CaretModeChanged;
			_textEditor.ActiveTextAreaControl.TextArea.LostFocus += TextArea_LostFocus;
			_textEditor.ActiveTextAreaControl.TextArea.KeyDown += TextArea_KeyDown;
			_textEditor.Document.DocumentChanged += Document_DocumentChanged;
			_textEditor.Document.UndoStack.ActionRedone += UndoStack_ActionRedone;
			_textEditor.Document.UndoStack.ActionUndone += UndoStack_ActionRedone;

			_textEditor.ActiveTextAreaControl.TextArea.SelectionManager.SelectionChanged += TextArea_SelectionChanged;
			_textEditor.ActiveTextAreaControl.TextArea.MouseClick += TextArea_MouseClick;

			// Add the Editor...
			Controls.Add(_textEditor);
			Count++;
		}

		private void Initialize()
		{
			_findPosition = -1;

			//m_ToolTip = new HtmlToolTip(this);
			//m_Project = string.Empty;
			_autoComplete = new GListBox();

			//MdiParent = main;

			_changed = false;

			// Delegates...
			_loadFileDelegate = DelReload;
			_closeDelegate = DelClose;

			//previousMarkers = new List<TextMarker>();
		}

		private void InitializeComponent()
		{
			this.SuspendLayout();
			//
			// TextEditor
			//
			this.ClientSize = new System.Drawing.Size(301, 233);
			this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
			this.Name = "TextEditor";
			this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.TextEditor_FormClosed);
			this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.TextEditor_FormClosing);
			this.ResumeLayout(false);
		}

		/// <summary>
		/// Removes the * at the front of a changed document...
		/// </summary>
		private void RemoveChangeStar()
		{
			if (TabText.IndexOf('*') == 0) {
				TabText = TabText.Substring(1);
			}
		}

		/// <summary>
		/// Removes any previousily highlighted words and clears the internal list of
		/// markers
		/// </summary>
		public void ClearAllMarkers()
		{
			_textEditor.ActiveTextAreaControl.Document.MarkerStrategy.RemoveAll();
			_textEditor.Refresh();
		}

		/// <summary>
		/// Grabs the files dropped in the Editor...
		/// </summary>
		/// <param name="sender">Text Area</param>
		/// <param name="e">Events</param>
		private void TextArea_DragDrop(object sender, DragEventArgs e)
		{
			var files = (string[])e.Data.GetData(DataFormats.FileDrop);
			foreach (string file in files) {
				string filePath = file;
				string fileName = Path.GetFileName(file);
				Icon fileIcon = Host.GetFileIcon( filePath, false);

				_pluginHost.CreateEditor( filePath,  fileName,  fileIcon, this);
			}
			_mainForm.Focus();
		}

		private void TextArea_KeyDown(object sender, KeyEventArgs e)
		{
			//
			//Auto Complete...
			//
			/*
			   if (Controls.Contains(m_AutoComplete))
			   {
			    switch (e.KeyCode)
			    {
			        case Keys.Enter:
			        case Keys.Space:
			        case Keys.Oemcomma:
			        case Keys.OemMinus:
			        case Keys.OemOpenBrackets:
			        case Keys.OemPeriod:
			        case Keys.Oemplus:
			        case Keys.OemSemicolon:
			            Controls.Remove(m_AutoComplete);
			            break;
			    }
			   }

			   if (e.KeyCode == Keys.B)
			   {
			    this.Controls.Add(this.m_AutoComplete);
			    this.m_AutoComplete.Location = new Point(this.m_Editor.ActiveTextAreaControl.Caret.ScreenPosition.X,
			        this.m_Editor.ActiveTextAreaControl.Caret.ScreenPosition.Y + this.m_Editor.Font.Height);
			    this.m_AutoComplete.Size = new Size(100, 100);
			    this.m_AutoComplete.BringToFront();
			    this.m_AutoComplete.Show();
			   }
			   else
			   {
			    if (this.Controls.Contains(this.m_AutoComplete))
			    {
			        this.Controls.Remove(this.m_AutoComplete);
			    }
			   }*/
		}

		private void TextArea_LostFocus(object sender, EventArgs e)
		{
			if (_toolTip != null && _toolTip.Visible) _toolTip.Hide();
		}

		private void TextArea_MouseDown(object sender, MouseEventArgs e)
		{
            if (_toolTip == null) _toolTip = new HtmlToolTip(this);

			if (_toolTip.Visible) {
                //m_ToolTip.Close();
                _toolTip.Hide();
            }
			if (e.Button == MouseButtons.Left) {
				if (ModifierKeys == Keys.Alt) {
					int pos = _textEditor.ActiveTextAreaControl.Caret.Offset;
					int before = pos;
					int after = pos;
					while (CheckStop(_textEditor.Document.TextContent[before])) {
						before--;
					}
					before++;
					while (CheckStop(_textEditor.Document.TextContent[after])) {
						after++;
					}

					if (after > before) {
						if (ModifierKeys == Keys.Control) {
							_textEditor.ActiveTextAreaControl.SelectionManager.SetSelection(
							        _textEditor.Document.OffsetToPosition(before), _textEditor.Document.OffsetToPosition(after));
						} else if (ModifierKeys == Keys.Alt) {
							#region  Look Up Word

							string text = _textEditor.Document.TextContent.Substring(before, after - before);
							StringBuilder html = new StringBuilder("<table><tr><th colspan=\"2\">" + text + "</th></tr><tr>");
							int count = 0;
							if (!string.IsNullOrEmpty(_project)) {
								string lookup = _mainForm.LookUpProject(text, _project);
								if (!lookup.Equals("<ul></ul>")) {
									count++;
								}
								html.Append("<tr><td colspan=\"2\">" + lookup + "</td></tr>");
							}
							var reg = new Regex(text);
							MatchCollection mc = reg.Matches(_textEditor.Document.TextContent);
							if (mc.Count > 1) {
								var lines = new ArrayList();
								html.Append("<tr><td colspan=\"2\">References in Document:</td></tr>");
								foreach (Match m in mc) {
									int lineNum = _textEditor.Document.GetLineNumberForOffset(m.Index);
									if (lineNum != _textEditor.ActiveTextAreaControl.Caret.Line && !lines.Contains(lineNum)) {
										lines.Add(lineNum);
										lineNum++;
										count++;
										LineSegment line = _textEditor.Document.GetLineSegmentForOffset(m.Index);

										html.Append("<tr><td valign=\"top\" align=\"right\"><a h=\"\"><span id=\"line\">" + lineNum + "</span></a></td><td>" +
										        _textEditor.Document.TextContent.Substring(line.Offset, line.TotalLength) + "</td></tr>");
									}
								}
								html.Append("</table>");
							}
							if (count > 0) {
								_toolTip.HTML = html.ToString();
								_toolTip.Location = MousePosition;
								_toolTip.Show();
							}

							#endregion
						}
					}
				}
			}
		}

		/// <summary>
		/// Occurs when a selection is made in the text editor.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void TextArea_SelectionChanged(object sender, EventArgs e)
		{
			SelectionManager selectionManager = _textEditor.ActiveTextAreaControl.SelectionManager;
			if (selectionManager.SelectedText.Length > 2) {
				if (HighlightMatchingWords(selectionManager.SelectedText))
                    selectionManager.ClearSelection();
			}
		}

		private void TextArea_MouseClick(object sender, EventArgs e)
		{
			ClearAllMarkers();
		}

		private void TextEditor_FormClosed(object sender, FormClosedEventArgs e)
		{
			--Count;
		}

		private void TextEditor_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (CloseTab() == false) e.Cancel = true;
		}

		private void UndoStack_ActionRedone(object sender, EventArgs e)
		{
			_textEditor.ActiveTextAreaControl.TextArea.Invalidate();
		}

		/// <summary>
		/// Occurs when the file is Changed...
		/// </summary>
		/// <param name="sender">FileSystemWatcher</param>
		/// <param name="e">Events</param>
		private void m_FSW_Changed(object sender, FileSystemEventArgs e)
		{
			Invoke(this._loadFileDelegate, new object[] { e.FullPath });
		}

		/// <summary>
		/// Occurs when the file is deleted...
		/// </summary>
		/// <param name="sender">FileSystemWatcher</param>
		/// <param name="e">Events</param>
		private void m_FSW_Deleted(object sender, FileSystemEventArgs e)
		{
			Invoke(_closeDelegate);
		}

		/// <summary>
		/// Occurs when the file is Renamed...
		/// </summary>
		/// <param name="sender">FileSystemWatcher</param>
		/// <param name="e">Events</param>
		private void m_FSW_Renamed(object sender, RenamedEventArgs e)
		{
			Invoke(_loadFileDelegate, new object[] { e.FullPath });
		}

        protected override void OnPaint(PaintEventArgs e)
        {
            //this.SuspendLayout();
            base.OnPaint(e);
            //this.ResumeLayout();
        }


		#endregion Methods

        #region IDisposable Members

        void IDisposable.Dispose()
        {
            //TODO: Implement the Dispose method of SourceEditor
        }

        #endregion
    }
}